﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;

namespace UnrarService
{
    /// <summary>
    /// Beschreibt ein Komplettes Archiv inkl. aller ArchivDateien.
    /// </summary>
    public class FileType
    {
        #region Static
        /// <summary>
        /// Gibt den Filenamen ohne rar und ohne Part001... zurück.
        /// </summary>
        public static string ClearFileName(string filename)
        {
            return Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(ClearRarFileName(filename)));
        }

        /// <summary>
        /// Überprüft einen Dateinamen, ob es sich um einen "reinen" rar-Dateinamen handelt. z.B. "movieXXx.part1.rar.html" wird umgewandelt in "movieXXx.part1.rar" für einen Sauberen RarFilenamen
        /// </summary>
        /// <param name="filename">Dateiname der angepasst werden soll.</param>
        /// <returns>Clear Rarfilename</returns>
        public static string ClearRarFileName(string filename)
        {
            //Prüfen ob die Datei rar enthält und darauf endet.
            if (!filename.ToLower().EndsWith(".rar") && filename.ToLower().Contains(".rar"))
            {
                //Prüfen ob auch der Gesamtstring lang genug ist um ihn abzuschneiden
                if (filename.Length > filename.ToLower().LastIndexOf(".rar") + 4)
                {
                    return filename.Remove(filename.ToLower().LastIndexOf(".rar") + 4); ;
                }
            }

            return filename;
        }

        #endregion

        #region Member
        private string _filename;
        private string _firstArchiveFilePath;
        private SortedList<int, FileTypeInfo> _parts;

        #endregion

        #region Properties
        /// <summary>
        /// Die Liste aus allen ArchivDateien
        /// </summary>
        public SortedList<int, FileTypeInfo> Parts
        {
            get { return _parts; }
            set { _parts = value; }
        }

        /// <summary>
        /// Der Name des ersten Archivs, wird fürs Entpacken benötigt.
        /// </summary>
        public string FirstArchiveFilePath
        {
            get { return _firstArchiveFilePath; }
        }
        #endregion

        #region Kontruktor
        /// <summary>
        /// Initialieren des FileTypes
        /// </summary>
        /// <param name="filePath">Der Pfad der Datei</param>
        public FileType(string filePath)
        {
            _filename = ClearFileName(filePath);
            Parts = new SortedList<int, FileTypeInfo>();
            System.IO.FileInfo fileInfo = new FileInfo(filePath);
            int partNumber = GetRarPartNumber(filePath);
            Parts.Add(partNumber, new FileTypeInfo(fileInfo.Length, partNumber, filePath));
        }
        #endregion

        #region Functions/Subs
        /// <summary>
        /// Überprüft den aktuellen Entpackstatus, für das gesammte Archiv. Ob bereits alle Dateien auf "Ready" == True stehen.
        /// Wenn dies der Fall ist, kann das Archiv entpackt werden.
        /// </summary>
        /// <returns>TRUE->Archiv ist komplett "heruntergeladen" und kann entpackt werden | FALSE->Noch nicht komplett "heruntergeladen"</returns>
        public bool CheckEntpackStatus()
        {
            long filesize = 0;
            int currentPart = 1;

            //Das es sich um eine SortedListe handelt, ist diese nach den Partnummern sortiert
            foreach (KeyValuePair<int, FileTypeInfo> ePart in Parts)
            {
                //Prüft ob die jeweilige File auch "Ready" ist, d.h. komplett heruntergeladen wurde.
                if (ePart.Value.PartNumber == currentPart && ePart.Value.Ready)
                {
                    //Die Dateigröße der ersten Datei wird sich gemerkt
                    if (ePart.Value.PartNumber == 1)
                    {
                        filesize = ePart.Value.Size;
                    }

                    //sobald eine Datei kleiner ist, wie die erste Datei, dann handelt es sich um das Archivende und es kann entpackt werden
                    if (ePart.Value.Size < filesize)
                    {
                        return true;
                    }

                    currentPart++;
                }
                //Kann auch runtergeladen werden, denn hierbei handelt es sich um ein einzelnes Rar Archiv ohne Nummern.
                else if (ePart.Value.PartNumber == int.MinValue)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            return false;
        }

        /// <summary>
        /// Hinzufügen einer neuen Archivdatei zur Archivliste
        /// </summary>
        /// <param name="filePath">Der Pfad für die Archivdatei</param>
        /// <param name="ready">Gibt an ob die Datei komplett "Heruntergeladen" wurde, d.h. ob auf sie zugegriffen werden kann.</param>
        public void AddFileName(string filePath, bool ready)
        {
            System.IO.FileInfo fileInfo = new FileInfo(filePath);
            int partNumber = GetRarPartNumber(filePath);

            if (!Parts.ContainsKey(partNumber))
            {
                Parts.Add(partNumber, new FileTypeInfo(fileInfo.Length, partNumber, filePath));
            }
            else
            {
                Parts[partNumber].Ready = true;
                Parts[partNumber].Size = fileInfo.Length;
            }
        }

        /// <summary>
        /// Löschen der Dateien, wenn diese erfolgreich entpackt wurden
        /// </summary>
        public void DeleteRarFiles()
        {
            //Alle Parts durchgehen und löschen
            foreach (KeyValuePair<int, FileTypeInfo> ePart in Parts)
            {
                if (System.IO.File.Exists(ePart.Value.FullPathName))
                {
                    System.IO.File.Delete(ePart.Value.FullPathName);
                }
            }
        }

        /// <summary>
        /// Sucht die PartNummer der RarDatei heraus.
        /// </summary>
        /// <param name="filePath">Dateiname inkl Pfad, aus dem die Partnummer herausgesucht werden soll</param>
        /// <returns>int.MinValue Bei einem Fehler, bzw. wenn keine Partnummer gefunden werden konnte.</returns>
        private int GetRarPartNumber(string filePath)
        {
            //Aufpassen, das der Dateiname auch weitgenug "gekürzt wird, damit die Partnummern ausgelesen werden können, sehr wichtig wenn z.b. eine Datei auf *.part1.rar.html endet.
            string fileName = Path.GetFileNameWithoutExtension(ClearRarFileName(Path.GetFileName(filePath))).ToLower();

            //extrahiert die reine Nummer aus dem Filenamen
            if (fileName.Contains("part"))
            {
                fileName = fileName.Substring(fileName.LastIndexOf("part")).Replace("part", "");
            }

            int number = int.MinValue;

            try
            {
                number = int.Parse(fileName);
            }
            catch (Exception)
            {
                number = int.MinValue;
            }


            //Den Namen der ersten Archievdatei speichern, wird zum Entpacken benötigt.
            if (number == 1 || number == 0 || number == int.MinValue)
            {
                _firstArchiveFilePath = filePath;
            }

            return number;
        }
        #endregion
    }
}
